package views.components;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;

import utils.MessageUtils;
import utils.ReflectionUtils;
import views.interfaces.IParameter;

import com.vaadin.addon.jpacontainer.JPAContainer;
import com.vaadin.data.Item;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;
import com.vaadin.ui.ComboBox;
import com.vaadin.ui.Notification;
import com.vaadin.ui.Notification.Type;
import com.vaadin.ui.Table;
import com.vaadin.ui.Table.ColumnGenerator;

import controllers.control.BaseController;
import controllers.interfaces.IExecOption;
import dao.interfaces.IBase;

@SuppressWarnings("serial")
/**
 * Tabla per a vaadin que exten de PagedTable implementa IParameter i columnGenerator
 * @author informatica
 */
public class TablaPaginada extends views.components.PagedTable implements
		IParameter, ColumnGenerator, ClickListener {
	private String storedId = null;
	private Class<IBase> myClass;
	private Class<BaseController> myControllerClass;

	// Nivell de seguritat del usuari actual.
	private int secLevel;

	// id y ComboBox que han sigut seleccionats
	private HashMap<Object, ComboBox> seleccio;

	// String I18n com a key i key de internacionalitzacio
	// degut a que seleccio esta en i18n
	private HashMap<String, String> conversioKeyaI18n;

	// accions del controlador amb secLevel
	private HashMap<String, Integer> actionsController;
	private JPAContainer<IBase> jpaContainer;

	public TablaPaginada(Class<IBase> myClass,
			Class<BaseController> myControllerClass,
			JPAContainer<IBase> jpaContainer, IParameter caller, int secLevel,
			String viewName) {
		super();
		this.myClass = myClass;
		this.myControllerClass = myControllerClass;
		this.jpaContainer = jpaContainer;
		this.secLevel = secLevel;
		setContainerDataSource(jpaContainer);
		setImmediate(true);
		seleccio = new HashMap<Object, ComboBox>();

		// definim les opcions que tindra el comboBox de la tabla

		getActions();

		// agafe les columnes que seran visibles per esta @view en myClass

		ArrayList<String> columnes = ReflectionUtils.getViewFields(myClass,
				viewName);

		// anyadim la columna generada del comboBox
		// accio que realitzara el boto de executar
		columnes.add(0, "seleccio");

		for (String columna : columnes)
			if (columna.contains("."))
				jpaContainer.addNestedContainerProperty(columna);

		addGeneratedColumn("seleccio", this);
		setVisibleColumns(columnes.toArray());

		// creem les cabeceres de les columnes de la tabla internacionalitzades
		String[] headers = new String[columnes.size()];
		for (int i = 0; i < columnes.size(); i++)
			headers[i] = MessageUtils.getI18n(columnes.get(i));

		setColumnHeaders(headers);

	}

	public void refresh() {
		jpaContainer.refresh();
	}

	/**
	 * Crea conversioKeyaI18n y actionsController
	 */
	private void getActions() {

		conversioKeyaI18n = new HashMap<String, String>();
		actionsController = new HashMap<String, Integer>();

		// recorrem @action de myControllerClass
		// ens els guardem si tenim permisos

		for (Entry<String, Integer> e : ReflectionUtils.getActionAnnotations(
				myControllerClass).entrySet()) {

			if (e.getValue() <= secLevel) {

				actionsController.put(e.getKey(), e.getValue());
				conversioKeyaI18n.put(MessageUtils.getI18n(e.getKey()),
						e.getKey());

			}
		}

	}

	@Override
	public Object generateCell(Table source, final Object itemId,
			Object columnId) {

		// TODO fer que nomes es cree una volta i es copie la resta
		final ComboBox comboBox = new ComboBox();

		for (String key : conversioKeyaI18n.keySet())
			comboBox.addItem(key);

		comboBox.setImmediate(true);
		comboBox.setNullSelectionAllowed(true);

		// creem un valor nul,la seua representacio y el seleccionem

		String nullitem = MessageUtils.getI18n("no_res_seleccionat");
		comboBox.addItem(nullitem);
		comboBox.setNullSelectionItemId(nullitem);
		comboBox.setWidth("140px");
		comboBox.addValueChangeListener(new ValueChangeListener() {

			@Override
			public void valueChange(
					com.vaadin.data.Property.ValueChangeEvent event) {

				if (comboBox.getValue() != null)
					seleccio.put(itemId, comboBox);
				else
					seleccio.remove(itemId);

			}
		});

		return comboBox;
	}

	@Override
	public void buttonClick(ClickEvent event) {

		// si sa marcat alguna opcio al desplegable

		if (seleccio.size() > 0) {

			Object clave;
			ComboBox combo;
			String valor, valorI18n;
			Entry<Object, ComboBox> entry;
			Item item;

			Iterator<Entry<Object, ComboBox>> itSeleccio = seleccio.entrySet()
					.iterator();
			// recorrem els combos seleccionats
			// comparem seu valor amb accions del controlador
			// si coincideix agafem el item
			// executem la accio en el controlador
			while (itSeleccio.hasNext()) {

				entry = itSeleccio.next();
				clave = entry.getKey();
				combo = entry.getValue();
				valorI18n = combo.getValue().toString();
				valor = conversioKeyaI18n.get(valorI18n);

				for (String action : actionsController.keySet()) {

					if (action.equalsIgnoreCase(valor)) {

						item = getItem(clave);

						try {

							IExecOption controller = myControllerClass
									.newInstance();

							controller.exeOption(action, item, jpaContainer);
							break;

						} catch (Exception e) {
							Notification.show((e.getCause() != null) ? e
									.getCause().getMessage() : e.getMessage(),
									Type.ERROR_MESSAGE);
							e.printStackTrace();
						}

					}

				}
				// em cargue el entry i fique el combo a nulo
				itSeleccio.remove();
				combo.setValue(null);
			}

			// si seleccio te tamany 0
		} else {
			Notification.show(MessageUtils.getI18n("noResSeleccionat"));
		}
	}

	@Override
	public String getParameter() {
		return storedId;
	}

	@Override
	public void setParameter(String parameter) {
		this.storedId = parameter;
	}

	public Class<IBase> getMyClass() {
		return myClass;
	}

	public JPAContainer<IBase> getJpaContainer() {
		return jpaContainer;
	}

}